<cfcomponent displayname="QueryDriver" hint="This class is a dictionary driver to manager Query Object" output="false">
	<cfscript>
		/**
		* 	Domain manipulation Method
		* 	@name select
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-21
		*	@return Domain
		**/
		public Query function select( Query problem , Any argument ) {
			return this.executeQueryOfQuery( recordSet : arguments.problem , filter : arguments.argument );
		}

		/**
		* 	Domain random Method
		* 	@name random
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-21
		*	@return Query
		**/
		public Query function random( Query problem ) {
			var arrDataSet 	   	= ArrayNew(1);
			var arrResult  	   	= ArrayNew(1);
			var recordSet  	   	= arguments.problem;
			var fieldList  	   	= ListToArray( recordSet.ColumnList );
			var structTemp  	= {};
			var randomizedQuery	= QueryNew( recordSet.ColumnList );
			var totalItensArray = recordSet.RecordCount;
			var indexRemove	   	= 0;

			arrDataSet = this.asArray( data : recordSet );

			for( var idx = 1; idx <= totalItensArray; idx++ ) {
				indexRemove  = RandRange( 1, ( ( totalItensArray + 1 ) -idx ) );
				arrResult[ idx ] = arrDataSet[ indexRemove ];
				ArrayDeleteAt( arrDataSet , indexRemove );
			}

			for( var row in arrResult ) {
				QueryAddRow( randomizedQuery );

				for( var field in fieldList ) {
					QuerySetCell( randomizedQuery , field , row[ field ] );
				}
			}

			return randomizedQuery;
		}

		/**
		* 	Domain determin sort field Method
		* 	@name asc
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-21
		*	@return String
		**/
		public String function asc( String field ) {
			var order = arguments.field & " ASC ";

			return order;
		}

		/**
		* 	Domain determin sort field Method
		* 	@name desc
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-21
		*	@return String
		**/
		public String function desc( String field ) {
			var order = arguments.field & " DESC ";

			return order;
		}

		/**
		* 	Domain sort data Method
		* 	@name sort
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-21
		*	@return Query
		**/
		public Query function sort( Query recordSet , String filter ) {
			return this.sortQueryOfQuery( recordSet : arguments.recordSet , filter : arguments.filter );
		}

		/**
		* 	Domain apply operator function Method
		* 	@name operator
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-21
		*	@return String
		**/
		public String function operator( String argument ) {
			return this.createOperation( arguments.argument );
		}

		/**
		* 	Domain return the delimiter to operation filter Method
		* 	@name getOperationDelimiter
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-21
		*	@return String
		**/
		public String function getOperationDelimiter() {
			return ' AND ';
		}

		/**
		* 	Domain cast some query data to array Method
		* 	@name asArray
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-22
		*	@return Array
		**/
		public Array function asArray( Query data ) {
			var arrDataSet  = [];
			var structTemp	= {};
			var recordSet   = arguments.data;
			var fieldList 	= recordSet.columnList;

			loop query="recordSet" {
				structTemp = {};

				for( var field in fieldList ) {
					structTemp[ field ] =  recordSet[ field ];
				}

				ArrayAppend( arrDataSet , structTemp );
			}

			return arrDataSet;
		}

		/**
		* 	cast data to query Method
		* 	@name asQuery
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-25
		*	@return Query
		**/
		public Query function asQuery( Any data ) {
			var adapter = "";

			if( IsQuery( arguments.data ) == true ) {
				return arguments.data;
			}
			else {
				adapter = this.getAdapter( data : arguments.data )
			}

			return adapter.asQuery( data : arguments.data );
		}

		/**
		* 	get an item of object Method
		* 	@name getItem
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-22
		*	@return Query
		**/
		public Query function getItem( Query data , String field ,Any item ) {
			var q_recordSet	= QueryNew( arguments.field );
			var item		= arguments.item;
			var recordSet	= arguments.data;

			loop query="recordSet" {
				QueryAddRow( q_recordSet );

				QuerySetCell( q_recordSet , arguments.field , q_recordSet[ arguments.field ] );
			}

			// if exists some filter data, execute a query of query
			if( Len( Trim( item ) ) gt 0 ) {
				queryParam 	= ( IsNumeric( item ) == true || IsDate( item ) == true ) ? arguments.field & " = " & item : arguments.field & " = '" & item & " ' ";
				q_recordSet = this.executeQueryOfQuery( q_recordSet , queryParam );
			}

			return q_recordSet;
		}

		/**
		* 	set data in the object Method
		* 	@name add
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-29
		*	@return Query
		**/
		public Query function add( Query source , Query data ) {
			var q_RecordSet		 = arguments.source;
			var listColumnOrigin = q_RecordSet.columnList;
			var data			 = arguments.data;
			var listColumnData	 = data.columnList;
			var listColumnFinal  = "";

			for( var idx = 1; ListLen( listColumnData ); idx++ ) {
				variables.field = listColumnData[idx];
				if( ListFindNoCase( listColumnOrigin , ListGetAt( variables.field, 0 ) ) > 0 ) {
					listColumnFinal = ListAppend( listColumnFinal , variables.field );
				}
			}

			if( ListLen( listColumnOrigin ) == ListLen( listColumnFinal ) ) {
				variables.error = Application.instance.factory.getModels("Error");
				variables.error.handlerError( Application.config.customExceptionUser , "The object data not contains the same fields of the source object" );
			}

			loop query="data" {
				QueryAddRow( q_RecordSet );

				for( var idx = 1; ListLen( listColumnFinal ); idx++ ) {
					variables.field = ListGetAt( listColumnFinal , idx );
					QuerySetCell( q_RecordSet , variables.field , data[ variables.field ] );
				}
			}

			return q_RecordSet;
		}

		/**
		* 	sum data from some attribute object Method
		* 	@name sumFrom
		* 	@access public
		* 	@author Paulo Teixeira
		*	@date 2012-05-29
		*	@return Query
		**/
		public Query function sumFrom( Query source , String data ) {
			var q_RecordSet	= arguments.source;
			var field		= arguments.data;

			q_RecordSet = this.sumQueryOfQuery( recordSet : q_RecordSet , filter : field );

			return q_RecordSet;
		}

		/**
		* 	Domain create some string filter applying the operator Method
		* 	@name createOperation
		* 	@access private
		* 	@author Paulo Teixeira
		*	@date 2012-05-29
		*	@return String
		**/
		private String function createOperation( argument ) {
			var structParametro = {};

			if( ListLen( arguments.argument , "$|" ) < 3 ) {
				variables.error   = Application.instance.factory.getModels("Error");
				variables.error.handlerError( Application.config.customExceptionUser ,"To solve the problem with query type data, is necessary passing the field name and a param data" );
			}

			structParametro = {
					field : ListGetAt( arguments.argument , 1 , "$|" ) ,
				   indice : ListGetAt( arguments.argument , 2 , "$|" ) ,
				argumento : ListGetAt( arguments.argument , 3 , "$|" )
			};

			switch( structParametro.indice ) {
				case 'EQ' :
					return structParametro.field & " = "  & PreserveSingleQuotes( structParametro.argumento );
				break;
				case 'NEQ' :
					return structParametro.field & " != " & PreserveSingleQuotes( structParametro.argumento );
				break;
				case 'LT' :
					return structParametro.field & " < "  &	PreserveSingleQuotes( structParametro.argumento );
				break;
				case 'LTE' :
					return structParametro.field & " <= " & PreserveSingleQuotes( structParametro.argumento );
				break;
				case 'GT' :
					return structParametro.field & " > "  &	PreserveSingleQuotes( structParametro.argumento );
				break;
				case 'GTE' :
					return structParametro.field & " >= " & PreserveSingleQuotes( structParametro.argumento );
				break;
			}
		}

		/**
		* 	Domain get adapter intance Method
		* 	@name getAdapter
		* 	@access private
		* 	@author Paulo Teixeira
		*	@date 2012-05-25
		*	@return Any
		**/
		private Any function getAdapter( Any data ) {
			if( IsArray( arguments.data ) == true ) {
				return Application.instance.factory.getDitionary("ArrayDriver");
			}
			else if( IsStruct( arguments.data ) == true ) {
				return Application.instance.factory.getDitionary("StructDriver");
			}
			else if( ListLen( arguments.data ) gt 0 ) {
				return Application.instance.factory.getDitionary("ListDriver");
			}
			else {
				variables.error = Application.instance.factory.getModels("Error");
				variables.error.handlerError( Application.config.customExceptionUser , "The object data not is in a valid data type or is empty" );
			}
		}
	</cfscript>

	<!---
	* Domain execute a query of query method
	* @name executeQueryOfQuery
	* @access Private
	* @author Paulo Teixeira
	* @date 2012-05-21
	* @return query
	--->
	<cffunction name="executeQueryOfQuery" access="private" output="false" returntype="Query">
		<cfargument name="recordSet" type="Query"  required="true" 				hint="RecordSet of the data to be filtering" />
		<cfargument name="filter" 	 type="String" required="false" default="" 	hint="Arguments to execute a filtering in a query data" />

		<cfquery name="q_RecordSet" dbtype="Query">
			SELECT * FROM arguments.recordSet
			<cfif Len( Trim( arguments.filter ) ) gt 0>
				WHERE #PreserveSingleQuotes( arguments.filter )#
			</cfif>
		</cfquery>

		<cfreturn q_RecordSet />
	</cffunction>

	<!---
	* Domain sort a query of query method
	* @name sortQueryOfQuery
	* @access Private
	* @author Paulo Teixeira
	* @date 2012-05-21
	* @return query
	--->
	<cffunction name="sortQueryOfQuery" access="private" output="false" returntype="Query">
		<cfargument name="recordSet" type="Query"  required="true" hint="RecordSet of the data to be filtering" />
		<cfargument name="filter" 	 type="String" required="true" hint="Arguments to execute order by in a query data" />

		<cfquery name="q_RecordSet" dbtype="Query">
			SELECT * FROM arguments.recordSet ORDER BY #PreserveSingleQuotes( arguments.filter )#
		</cfquery>

		<cfreturn q_RecordSet />
	</cffunction>

	<!---
	* Domain execute a sum query of query method
	* @name sumQueryOfQuery
	* @access Private
	* @author Paulo Teixeira
	* @date 2012-05-29
	* @return query
	--->
	<cffunction name="sumQueryOfQuery" access="private" output="false" returntype="Query">
		<cfargument name="recordSet" type="Query"  required="true" hint="RecordSet of the data to be filtering" />
		<cfargument name="filter" 	 type="String" required="true" hint="Arguments to execute a filtering in a query data" />

		<cfquery name="q_RecordSet" dbtype="Query">
			SELECT SUM( arguments.filter ) FROM arguments.recordSet
		</cfquery>

		<cfreturn q_RecordSet />
	</cffunction>
</cfcomponent>